﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Data.OleDb;
using System.Data;
using FileHelpers;
using System.Text.RegularExpressions;
using Visifire.Charts;
using Visifire.Commons;
using Microsoft.Windows.Controls;

namespace EvE_Asset_Stats
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private Dictionary<DateTime, DataTable> assetTables;

        public Window1()
        {
            InitializeComponent();
            assetTables = new Dictionary<DateTime, DataTable>();
        }

        private void uxOpenFileButton_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
            openFileDialog.DefaultExt = ".csv";
            openFileDialog.Filter = "EVE Asset Manager Export (.csv)|*.csv";

            Nullable<bool> result = openFileDialog.ShowDialog();
            Regex dateReg = new Regex("\\.*_(?<year>[0-9]{4})(?<month>[0-9]{2})(?<day>[0-9]{2})(?<hour>[0-9]{2})(?<minute>[0-9]{2})");

            if (result == true)
            {
                string filename = openFileDialog.FileName;
                Match fileDateTimeMatch = dateReg.Match(filename);
                DateTime assetDateTime = new DateTime(Int32.Parse(
                    fileDateTimeMatch.Groups["year"].ToString()), Int32.Parse(fileDateTimeMatch.Groups["month"].ToString()), Int32.Parse(fileDateTimeMatch.Groups["day"].ToString()),
                    Int32.Parse(fileDateTimeMatch.Groups["hour"].ToString()), Int32.Parse(fileDateTimeMatch.Groups["minute"].ToString()), 0);
                try
                {
                    assetTables.Add(assetDateTime, ReadCsvFileIn(filename));
                }
                catch (ArgumentException)
                {
                    //If the user is trying to add an asset file that is already in then do nothing
                }

                uxAssetDataTablesList.Items.Clear();
                foreach (DateTime dt in assetTables.Keys)
                {
                    uxAssetDataTablesList.Items.Add(dt.ToLongDateString() + " " + dt.ToLongTimeString());
                }
            }

            if (uxAssetDataTablesList.Items.Count > 1)
            {
                BuildMultipleDataTabs();
                uxReloadMultiDataButton.IsEnabled = true;
            }

        }

        /// <summary>
        /// Build the visualisations for multiple data sets.
        /// 
        /// Includes summary of the totals, a graph that shows the largest (ISK) location of assets.
        /// And tabs for tracking the value of the assets over time and the number of ships over time.
        /// </summary>
        private void BuildMultipleDataTabs()
        {
            uxVisualisationsTabControl.Items.Clear();            
            
            BuildMultipleSummary();
            BuildMultipleValueGraph();
            BuildMultipleShipGraph();

            uxVisualisationsTabControl.SelectedIndex = 0;
        }

        /// <summary>
        /// Build a graph that has the total number of ships and ISK totals over time.
        /// </summary>
        private void BuildMultipleShipGraph()
        {
            Dictionary<DateTime, int> numberOfShips = new Dictionary<DateTime, int>();
            Dictionary<DateTime, long> iskTotalOfShips = new Dictionary<DateTime, long>();


            foreach (DateTime dt in assetTables.Keys)
            {
                var shipAssetInfo =
                    from shipInfoTable in assetTables[dt].AsEnumerable()
                    where shipInfoTable.Field<string>("categoryName").Equals("Ship")
                    select new
                    {
                        Number = shipInfoTable.Field<int>("quantity"),
                        Price = shipInfoTable.Field<long>("basePrice"),
                        ItemType = "Ship"
                    }
                    ;

                var totalShipInfo =
                    from oldRow in shipAssetInfo
                    group oldRow by oldRow.ItemType into newRow
                    select new { ItemType = newRow.Key, TotalNumber = newRow.Sum(oldRow => oldRow.Number), TotalPrice = newRow.Sum(oldRow => oldRow.Price) }
                ;

                foreach (var ship in totalShipInfo)
                {
                    numberOfShips.Add(dt, ship.TotalNumber);
                    iskTotalOfShips.Add(dt, ship.TotalPrice);
                }
            }

            Chart numChart = new Chart();
            {
                numChart.Width = 750;
                numChart.Height = 350;
                numChart.Theme = "Theme1";
                numChart.AnimationEnabled = true;
                numChart.ColorSet = "VisiGray";
                Title t = new Title();
                t.Text = "Total Number of Ships";
                numChart.Titles.Add(t);
                // Specifc axis information
                Axis axisX = new Axis();
                axisX.Title = "Date";
                axisX.LineStyle = LineStyles.Solid;
                axisX.ValueFormatString = "f";
                axisX.IntervalType = IntervalTypes.Weeks;
                axisX.Interval = 1;
                numChart.AxesX.Add(axisX);
                Axis axisY = new Axis();
                axisY.Title = "Number of Ships";
                axisY.LineStyle = LineStyles.Solid;
                numChart.AxesY.Add(axisY);


                // Adding data points
                DataSeries ds = new DataSeries();
                ds.RenderAs = RenderAs.Line;
                ds.AxisYType = AxisTypes.Primary;
                ds.XValueFormatString = "f";
                foreach (DateTime dt in numberOfShips.Keys)
                {
                    DataPoint dp = new DataPoint();
                    dp.XValue = dt.ToString("f");
                    dp.YValue = numberOfShips[dt];
                    ds.DataPoints.Add(dp);
                }

                numChart.Series.Add(ds);
            }

            Chart iskChart = new Chart();
            {
                iskChart.Width = 750;
                iskChart.Height = 350;
                iskChart.Theme = "Theme1";
                iskChart.AnimationEnabled = true;
                iskChart.ColorSet = "VisiRed";
                Title t = new Title();
                t.Text = "Total ISK Value of All Ships";
                iskChart.Titles.Add(t);
                // Specifc axis information
                Axis axisX = new Axis();
                axisX.Title = "Date";
                axisX.LineStyle = LineStyles.Solid;
                axisX.ValueFormatString = "f";
                axisX.IntervalType = IntervalTypes.Weeks;
                axisX.Interval = 1;
                numChart.AxesX.Add(axisX);
                Axis axisY = new Axis();
                axisY.Title = "Base ISK Value of Ships";
                axisY.LineStyle = LineStyles.Solid;
                iskChart.AxesY.Add(axisY);


                // Adding data points
                DataSeries ds = new DataSeries();
                ds.RenderAs = RenderAs.Line;
                ds.AxisYType = AxisTypes.Primary;
                ds.XValueFormatString = "f";
                foreach (DateTime dt in iskTotalOfShips.Keys)
                {
                    DataPoint dp = new DataPoint();
                    dp.XValue = dt.ToString("f");
                    dp.YValue = iskTotalOfShips[dt];
                    ds.DataPoints.Add(dp);
                }

                iskChart.Series.Add(ds);
            }

            StackPanel sp = new StackPanel();
            sp.Children.Add(numChart);
            sp.Children.Add(iskChart);

            TabItem ti = new TabItem();
            ti.Header = "Ships Over Time";
            ti.Content = sp;

            uxVisualisationsTabControl.Items.Add(ti);

        }

        /// <summary>
        /// Build a graph that displays a stacked visualisation of the item types over time.
        /// </summary>
        private void BuildMultipleValueGraph()
        {
            Dictionary<string, Dictionary<DateTime, long>> catTotals = new Dictionary<string, Dictionary<DateTime, long>>();

            foreach (DateTime dt in assetTables.Keys)
            {
                //Dictionary<string, long> catTotals = new Dictionary<string, long>();

                var catRawData =
                    from categoryData in assetTables[dt].AsEnumerable()
                    orderby categoryData.Field<string>("categoryName")
                    select new
                    {
                        catType = categoryData.Field<string>("categoryName"),
                        catQuantity = categoryData.Field<int>("quantity"),
                        catPrice = categoryData.Field<long>("basePrice"),
                        catPortion = categoryData.Field<int>("portionSize")
                    }
                        ;

                foreach (var catData in catRawData)
                {
                    if (catTotals.ContainsKey(catData.catType))
                    {
                        if (catTotals[catData.catType].ContainsKey(dt))
                        {
                            catTotals[catData.catType][dt] += (catData.catQuantity * (catData.catPrice / catData.catPortion));
                        }
                        else
                        {
                            catTotals[catData.catType].Add(dt, (catData.catQuantity * (catData.catPrice / catData.catPortion)));
                        }
                    }
                    else
                    {
                        Dictionary<DateTime, long> catDate = new Dictionary<DateTime, long>();
                        catDate.Add(dt, catData.catQuantity * (catData.catPrice / catData.catPortion));
                        catTotals.Add(catData.catType, catDate);
                    }
                }
                //catTotals.Add(dt, catTotals);
            }

            //Build chart
            Chart catTotalsChart = new Chart();
            catTotalsChart.Width = 750;
            catTotalsChart.Height = 700;
            catTotalsChart.Theme = "Theme1";
            catTotalsChart.AnimationEnabled = true;
            Title t = new Title();
            t.Text = "ISK Value of Items Over Time";
            catTotalsChart.Titles.Add(t);
            // Specifc axis information
            Axis axisX = new Axis();
            axisX.Title = "Date";
            axisX.LineStyle = LineStyles.Solid;
            axisX.ValueFormatString = "f";
            axisX.IntervalType = IntervalTypes.Weeks;
            axisX.Interval = 1;
            catTotalsChart.AxesX.Add(axisX);
            Axis axisY = new Axis();
            axisY.Title = "ISK";
            axisY.LineStyle = LineStyles.Solid;
            catTotalsChart.AxesY.Add(axisY);


            // Adding data points
            foreach (string s in catTotals.Keys)
            {
                DataSeries ds = new DataSeries();
                ds.Name = s;
                ds.RenderAs = RenderAs.StackedArea;
                ds.AxisYType = AxisTypes.Primary;
                ds.XValueFormatString = "f";
                foreach (DateTime dt in catTotals[s].Keys)
                {
                    DataPoint dp = new DataPoint();
                    dp.XValue = dt.ToString("f");
                    dp.YValue = catTotals[s][dt];
                    ds.DataPoints.Add(dp);
                }

                catTotalsChart.Series.Add(ds);
            }

            TabItem ti = new TabItem();
            ti.Header = "Category Totals Over Time";
            ti.Content = catTotalsChart;
            uxVisualisationsTabControl.Items.Add(ti);

        }

        private void BuildMultipleSummary()
        {
            //throw new NotImplementedException();
        }

        private DataTable ReadCsvFileIn(string filename)
        {
            FileHelperEngine fhEngine = new FileHelperEngine(typeof(Asset));

            //Read in file
            return fhEngine.ReadFileAsDT(filename);
        }

        private void uxAssetDataTablesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (uxAssetDataTablesList.Items.Count == 0)
                return;

            DateTime dt;
            DateTime.TryParse(uxAssetDataTablesList.SelectedItem.ToString(), out dt);

            uxVisualisationsTabControl.Items.Clear();

            // Begin building visualisations
            BuildDataSumaryTab(assetTables[dt]);
            BuildTotalsGraphTab(assetTables[dt]);
            BuildCategoryGraphTab(assetTables[dt]);
            BuildRawDataGridTab(assetTables[dt]);

            uxVisualisationsTabControl.SelectedIndex = 0; // Should select the first tab
        }

        /// <summary>
        /// Diplay a cut down DataGrid of all the useful raw information.
        /// 
        /// Location, Name, Quantity, BaseISK and Meta level
        /// </summary>
        /// <param name="dataTable"></param>
        private void BuildRawDataGridTab(DataTable dataTable)
        {
            DataGrid data = new DataGrid();

            var basicData =
                from itemInfo in dataTable.AsEnumerable()
                select new { 
                    Name = itemInfo.Field<string>("typeName"), 
                    Quantity = itemInfo.Field<int>("quantity"),
                    ISK = (itemInfo.Field<long>("basePrice") / itemInfo.Field<int>("portionSize")) * itemInfo.Field<int>("quantity"), 
                    Meta = itemInfo.Field<int>("metaLevel"),
                    Location = itemInfo.Field<string>("locationName")
                }
                ;

            BindingGroup bg = new BindingGroup();

            data.ItemsSource = basicData.ToList();

            TabItem ti = new TabItem();
            ti.Header = "Raw Data";
            ti.Content = data;
            uxVisualisationsTabControl.Items.Add(ti);
        }

        /// <summary>
        /// Build a content control item that contains a graph displaying the distribution of all major categories (Ship, Module, Charge, etc.)
        /// </summary>
        /// <param name="dataTable"></param>
        private void BuildCategoryGraphTab(DataTable dataTable)
        {
            #region Build Data Points

            Dictionary<string, long> catTotals = new Dictionary<string, long>();

            var catRawData =
                from categoryData in dataTable.AsEnumerable()
                select new
                {
                    catType = categoryData.Field<string>("categoryName"),
                    catQuantity = categoryData.Field<int>("quantity"),
                    catPrice = categoryData.Field<long>("basePrice"),
                    catPortion = categoryData.Field<int>("portionSize")
                }
                    ;

            foreach (var catData in catRawData)
            {
                if (catTotals.ContainsKey(catData.catType))
                {
                    catTotals[catData.catType] = catTotals[catData.catType] += (catData.catQuantity * (catData.catPrice / catData.catPortion));
                }
                else
                {
                    catTotals.Add(catData.catType, catData.catQuantity * (catData.catPrice / catData.catPortion));
                }
            }

            #endregion

            #region Build Graph

            // Build the chart
            // Basic chart details
            Chart ch = new Chart();
            ch.Width = 750;
            ch.Height = 700;
            ch.Theme = "Theme1";
            ch.AnimationEnabled = true;
            //ch.ColorSet = "VisiRed";
            Title t = new Title();
            t.Text = "Number of Assets by Type";
            ch.Titles.Add(t);
            // Specifc axis information
            //Axis axisX = new Axis();
            //axisX.Title = "Locations";
            //axisX.LineStyle = LineStyles.Solid;
            //ch.AxesX.Add(axisX);
            //Axis axisY = new Axis();
            //axisY.Title = "Base ISK Price";
            //axisY.LineStyle = LineStyles.Solid;
            //ch.AxesY.Add(axisY);

            // Adding data points
            DataSeries ds = new DataSeries();
            ds.RenderAs = RenderAs.Pie;
            ds.AxisYType = AxisTypes.Primary;
            foreach (string key in catTotals.Keys)
            {
                DataPoint dp = new DataPoint();
                dp.AxisXLabel = key;
                dp.YValue = catTotals[key];
                ds.DataPoints.Add(dp);
            }

            ch.Series.Add(ds);

            TabItem ti = new TabItem();
            ti.Header = "Category Numbers";
            ti.Content = ch;
            uxVisualisationsTabControl.Items.Add(ti);

            #endregion
        }

        /// <summary>
        /// Build a content control that displays a basic summary of the contained data
        /// </summary>
        /// <param name="assetDataTable"></param>
        private void BuildDataSumaryTab(DataTable assetDataTable)
        {
            // Data points needed
            long totalBaseIsk = 0;
            int totalNumberOfShips = 0;
            long totalBaseIskValueOfShips = 0;
            float percentageOfModulesEquipped = 0.0F;
            float percentageOfModulesNotEquipped = 0.0F;

            float percentageOfMeta1Items = 0.0F; // Includes Meta 0 items
            float percentageOfMeta2Items = 0.0F;
            float percentageOfMeta3Items = 0.0F;
            float percentageOfMeta4Items = 0.0F;
            float percentageOfMeta5Items = 0.0F; // Includes Meta 5 and above items

            #region Get Total base ISK amount
            // Get Total base ISK amount
            var locationTotals =
                from assetInfo in assetDataTable.AsEnumerable()
                select new
                {
                    Location = assetInfo.Field<string>("locationName"),
                    Total = ((assetInfo.Field<long>("basePrice") / assetInfo.Field<int>("portionSize")) * assetInfo.Field<int>("quantity"))
                }
                ;

            foreach (var row in locationTotals)
            {
                totalBaseIsk += row.Total;
            }

            #endregion

            #region Get total number of ships and ISK total

            var allShips =
                from assetInfo in assetDataTable.AsEnumerable()
                where assetInfo.Field<string>("categoryName").Equals("Ship")
                select new { ShipName = assetInfo.Field<string>("typeName"), BasePrice = (assetInfo.Field<long>("basePrice") / assetInfo.Field<int>("portionSize")) }
                ;

            foreach (var ship in allShips)
            {
                totalNumberOfShips++;
                // TODO add a try catch here
                totalBaseIskValueOfShips += ship.BasePrice;
            }

            #endregion

            #region Get equipping percentages of modules

            int totalNumModules = 0;
            int numModulesNotEquipped = 0;

            var moduleData =
                from assetInfo in assetDataTable.AsEnumerable()
                where assetInfo.Field<string>("categoryName").Equals("Module")
                select new
                {
                    ModuleName = assetInfo.Field<string>("typeName"),
                    ModuleContainer = assetInfo.Field<string>("containerGroup"),
                    ModuleCount = assetInfo.Field<int>("quantity")
                }
                    ;

            foreach (var module in moduleData)
            {
                totalNumModules += module.ModuleCount;
                if (module.ModuleContainer.Equals("Hanger") || module.ModuleContainer.Contains("Container"))
                    numModulesNotEquipped += module.ModuleCount;
            }

            percentageOfModulesNotEquipped = (float)numModulesNotEquipped / (float)totalNumModules;
            percentageOfModulesEquipped = 1 - percentageOfModulesNotEquipped;


            #endregion

            #region Build Meta Info

            int totalNumItems = 0;
            int meta1 = 0;
            int meta2 = 0;
            int meta3 = 0;
            int meta4 = 0;
            int meta5 = 0;

            var metaInfo =
                from assetInfo in assetDataTable.AsEnumerable()
                select new { Quantity = assetInfo.Field<int>("quantity"), MetaLevel = assetInfo.Field<int>("metaLevel") }
                ;

            foreach (var item in metaInfo)
            {
                totalNumItems += item.Quantity;
                switch (item.MetaLevel)
                {
                    case 0:
                    case 1:
                        meta1 += item.Quantity;
                        break;
                    case 2:
                        meta2 += item.Quantity;
                        break;
                    case 3:
                        meta3 += item.Quantity;
                        break;
                    case 4:
                        meta4 += item.Quantity;
                        break;
                    default:
                        meta5 += item.Quantity;
                        break;
                }
            }

            percentageOfMeta1Items = (float)meta1 / (float)totalNumItems;
            percentageOfMeta2Items = (float)meta2 / (float)totalNumItems;
            percentageOfMeta3Items = (float)meta3 / (float)totalNumItems;
            percentageOfMeta4Items = (float)meta4 / (float)totalNumItems;
            percentageOfMeta5Items = (float)meta5 / (float)totalNumItems;

            #endregion

            #region Build content control

            StackPanel uxSummaryPanel = new StackPanel();
            uxSummaryPanel.VerticalAlignment = VerticalAlignment.Top;
            uxSummaryPanel.HorizontalAlignment = HorizontalAlignment.Left;


            Label totalIsk = new Label();
            totalIsk.Content = "Total Base ISK Value of Assets: " + totalBaseIsk.ToString("C");

            Label totalShips = new Label();
            totalShips.Content = "Total Number of Ships: " + totalNumberOfShips;

            Label totalShipIskValue = new Label();
            totalShipIskValue.Content = "Total Base ISK Value of All Ships: " + totalBaseIskValueOfShips.ToString("C");

            Label percentEquipped = new Label();
            percentEquipped.Content = "Total Number of Modules Equipped: " + (percentageOfModulesEquipped).ToString("P");

            Label percentNotEquipped = new Label();
            percentNotEquipped.Content = "Total Number of Modules Not Equipped: " + (percentageOfModulesNotEquipped).ToString("P");

            Label percentMeta1 = new Label();
            percentMeta1.Content = "Meta 1: " + percentageOfMeta1Items.ToString("P");

            Label percentMeta2 = new Label();
            percentMeta2.Content = "Meta 2: " + percentageOfMeta2Items.ToString("P");

            Label percentMeta3 = new Label();
            percentMeta3.Content = "Meta 3: " + percentageOfMeta3Items.ToString("P");

            Label percentMeta4 = new Label();
            percentMeta4.Content = "Meta 4: " + percentageOfMeta4Items.ToString("P");

            Label percentMeta5 = new Label();
            percentMeta5.Content = "Meta 5+: " + percentageOfMeta5Items.ToString("P");

            uxSummaryPanel.Children.Add(totalIsk);
            uxSummaryPanel.Children.Add(totalShips);
            uxSummaryPanel.Children.Add(totalShipIskValue);
            uxSummaryPanel.Children.Add(percentEquipped);
            uxSummaryPanel.Children.Add(percentNotEquipped);
            uxSummaryPanel.Children.Add(percentMeta1);
            uxSummaryPanel.Children.Add(percentMeta2);
            uxSummaryPanel.Children.Add(percentMeta3);
            uxSummaryPanel.Children.Add(percentMeta4);
            uxSummaryPanel.Children.Add(percentMeta5);

            TabItem ti = new TabItem();
            ti.Header = "Summary";
            ti.Content = uxSummaryPanel;
            uxVisualisationsTabControl.Items.Add(ti);
            #endregion


        }


        /// <summary>
        /// Build a graph displaying the totals of all of the locations
        /// </summary>
        /// <param name="assetDataTable"></param>
        private void BuildTotalsGraphTab(DataTable assetDataTable)
        {

            // Build the required data
            var locationTotals =
                from assetInfo in assetDataTable.AsEnumerable()
                select new
                {
                    Location = assetInfo.Field<string>("locationName"),
                    Total = ((assetInfo.Field<long>("basePrice") / assetInfo.Field<int>("portionSize")) * assetInfo.Field<int>("quantity"))
                }
                ;

            var groupedTotals =
                from oldRow in locationTotals
                group oldRow by oldRow.Location into newRow
                select new { Location = newRow.Key, LocationTotal = newRow.Sum(q => q.Total) }
                ;

            var orderedResult = (
                from row in groupedTotals
                orderby row.LocationTotal descending
                select new { Location = row.Location, LocationTotal = row.LocationTotal }
                ).Take(10);

            // Build the chart
            // Basic chart details
            Chart ch = new Chart();
            ch.Width = 750;
            ch.Height = 700;
            ch.Theme = "Theme1";
            ch.AnimationEnabled = true;
            ch.ColorSet = "VisiRed";
            Title t = new Title();
            t.Text = "Totals in All Locations";
            ch.Titles.Add(t);
            // Specifc axis information
            Axis axisX = new Axis();
            axisX.Title = "Locations";
            axisX.LineStyle = LineStyles.Solid;
            ch.AxesX.Add(axisX);
            Axis axisY = new Axis();
            axisY.Title = "Base ISK Price";
            axisY.LineStyle = LineStyles.Solid;
            axisY.Interval = 100000000;
            ch.AxesY.Add(axisY);
            

            // Adding data points
            DataSeries ds = new DataSeries();
            ds.RenderAs = RenderAs.Bar;
            ds.AxisYType = AxisTypes.Primary;
            foreach (var total in orderedResult.Reverse())
            {
                DataPoint dp = new DataPoint();
                string[] nameParts = total.Location.Split('-');
                if (nameParts.Length > 1)
                {
                    dp.AxisXLabel = nameParts[0] + ": " + nameParts[1];
                }
                else
                {
                    dp.AxisXLabel = nameParts[0];
                }
                dp.YValue = total.LocationTotal;
                ds.DataPoints.Add(dp);
            }

            ch.Series.Add(ds);

            TabItem ti = new TabItem();
            ti.Header = "Location Totals";
            ti.Content = ch;
            uxVisualisationsTabControl.Items.Add(ti);
        }

        /// <summary>
        /// Refresh the tabs for multiple data sets.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void uxReloadMultiDataButton_Click(object sender, RoutedEventArgs e)
        {
            BuildMultipleDataTabs();
        }

        private void uxOpenFolderButton_Click(object sender, RoutedEventArgs e)
        {

        }
    }
}
